#!/bin/sh

e2e_use_extensions() {
  true
}

e2e_test_install() {
  kubectl create namespace "$CLUSTER_NAMESPACE"

  PG_REPACK_VERSION="$(get_latest_version_of_extension pg_repack "${E2E_POSTGRES_VERSION%.*}")"

  create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 2 \
    --set-string 'cluster.postgres.extensions[0].name=pg_repack' \
    --set-string 'cluster.postgres.extensions[0].version'="$PG_REPACK_VERSION"

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  wait_pods_running "$CLUSTER_NAMESPACE" 2

  try_function wait_until eval '[ "$(kubectl get sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" -o json \
    | jq "select(.status != null and .status.podStatuses != null) | .status.podStatuses[]
      | select(.installedPostgresExtensions != null) | .installedPostgresExtensions[]
      | select(.name == \"pg_repack\") | length" \
    | jq -s "length")" = 2 ]'
  if "$RESULT"
  then
    success "pg_repack was installed"
  else
    fail "pg_repack was not installed"
  fi

  DBOPS_NAME=repack

  cat << EOF | kubectl create -f -
apiVersion: stackgres.io/v1
kind: SGDbOps
metadata:
  name: $DBOPS_NAME
  namespace: $CLUSTER_NAMESPACE
spec:
  sgCluster: $CLUSTER_NAME
  op: repack
EOF

  DBOPS_REPACK_CR="$(kubectl get sgdbops.stackgres.io -n "$CLUSTER_NAMESPACE" "$DBOPS_NAME" -o json \
    | jq 'del(.metadata.creationTimestamp) | del(.metadata.generation)
      | del(.metadata.resourceVersion) | del(.metadata.selfLink) | del(.metadata.uid)')"

  echo_raw "$DBOPS_REPACK_CR" > "$LOG_PATH/dbops-repack-cr.json"

  DBOPS_REPACK="$(cat "$LOG_PATH/dbops-repack-cr.json" \
    | jq 'del(.apiVersion) | del(.kind) | del(.status) | del(.metadata.annotations)' )"

  echo_raw "$DBOPS_REPACK" > "$LOG_PATH/dbops-repack.json"
}

e2e_test() {
  run_test "Check that a created repack can be accessed directly through the API" check_dbops_repack_directly

  run_test "Check that a created repack is included in the response" check_dbops_repack_in_list

  run_test "Check that a repack was removed after its deletion in the API" check_dbops_repack_removed

  run_test "Check repack is created with the API and is visible in the API" test_api_created_dbops_repack_is_visible

  run_test "Check repack is deleted with the API are reflected in the API" test_api_delete_dbops_repack_is_visible

  run_test "Constraint violations should be detected" test_constraint_violation_api_error

  run_test "User with wrong credentials should not be authenticated" test_authentication_api_error
}

check_dbops_repack_in_list() {
  if run_curl -r "stackgres/sgdbops" \
    | jq -r ".[] | select ( .metadata.namespace == \"$CLUSTER_NAMESPACE\" and .metadata.name == \"$DBOPS_NAME\") | .metadata.name" \
    | grep -q "^$DBOPS_NAME$"
  then
    echo "Dbops repack $DBOPS_NAME included in json response"
    return 0
  else
    echo "Dbops repack $DBOPS_NAME not included in json response"
    return 1
  fi
}

get_dbops_repack_http_status() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdbops/$DBOPS_NAME" -e "-LI -o /dev/null -w %{http_code}"
}

get_dbops_repack_pod_count() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdbops/$DBOPS_NAME" | jq '.pods | length'
}

check_dbops_repack_directly() {
  local HTTP_STATUS

  HTTP_STATUS="$(get_dbops_repack_http_status)"

  if [ "$HTTP_STATUS" -eq "200" ]
  then
    echo "Dbops repack $DBOPS_NAME was found bye the api"
    return 0
  else
    echo "Dbops repack $DBOPS_NAME was not found bye the api"
    return 1
  fi
}

remove_dbops_repack_cr_if_exists() {
  if kubectl get sgdbops.stackgres.io -n "$CLUSTER_NAMESPACE" "$DBOPS_NAME"
  then
    kubectl delete sgdbops.stackgres.io -n "$CLUSTER_NAMESPACE" "$DBOPS_NAME"

    wait_until eval '! kubectl get sgdbops.stackgres.io -n "$CLUSTER_NAMESPACE" "$DBOPS_NAME"'
  fi
}

check_dbops_repack_removed() {
  local HTTP_STATUS

  remove_dbops_repack_cr_if_exists

  if run_curl -r "stackgres/sgdbops" \
    | jq -r ".[] | select ( .metadata.namespace == \"$CLUSTER_NAMESPACE\" and .metadata.name == \"$DBOPS_NAME\") | .metadata.name" \
    | grep -q "^$DBOPS_NAME$"
  then
    echo "Dbops repack $DBOPS_NAME wasn't removed from cache"
    return 1
  else
    echo "Dbops repack $DBOPS_NAME was removed from cache"
    return 0
  fi

  HTTP_STATUS="$(run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdbops/$DBOPS_NAME" -e "-LI -o /dev/null -w %{http_code}")"

  if [ "$HTTP_STATUS" -eq "404" ]
  then
    echo "Dbops repack $DBOPS_NAME was not found by the api"
    return 0
  else
    echo "Dbops repack $DBOPS_NAME was found by the api"
    return 1
  fi
}

create_dbops_repack_with_api() {
  local HTTP_STATUS

  remove_dbops_repack_cr_if_exists

  HTTP_STATUS="$(run_curl -r "stackgres/sgdbops" -d "$LOG_PATH/dbops-repack.json" -e '-X POST -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
    return 0
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sgdbops" -d "$LOG_PATH/dbops-repack.json" -e '-X POST')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_api_created_dbops_repack_is_visible() {
  create_dbops_repack_with_api

  if kubectl get sgdbops.stackgres.io -n "$CLUSTER_NAMESPACE" "$DBOPS_NAME"
  then
    echo "Dbops repack created with the API"
  else
    echo "Dbops repack CR was not created"
    return 1
  fi

  check_dbops_repack_directly
}

delete_dbops_repack_with_api() {
  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sgdbops" -d "$LOG_PATH/dbops-repack.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
    return 0
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sgdbops" -d "$LOG_PATH/dbops-repack.json" -e '-X PUT')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_api_delete_dbops_repack_is_visible() {
  delete_dbops_repack_with_api

  if wait_until eval '[ "$(get_dbops_repack_http_status)" = "404" ]'
  then
    echo "Dbops repack removed from the API"
  else
    echo "Dbops repack wasn't removed from the API"
    return 1
  fi
}

test_constraint_violation_api_error() {
  local HTTP_STATUS

  INVALID_DBOPS="$(cat "$LOG_PATH/dbops-repack.json" | jq '.spec.sgCluster = null' )"
  echo_raw "$INVALID_DBOPS" > "$LOG_PATH/invalid-dbops-repack.json"

  HTTP_STATUS="$(run_curl -r "stackgres/sgdbops" -n "$CLUSTER_NAMESPACE"  -d "$LOG_PATH/invalid-dbops-repack.json" -e '-X POST -w %{http_code} -o /dev/null')"

  assert_string_equal "422" "$HTTP_STATUS"

  ERROR_RESPONSE="$(run_curl -r "stackgres/sgdbops" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/invalid-dbops-repack.json" -e '-X POST')"

  EXPECTED_ERROR_TYPE="constraint-violation"
  EXPECTED_ERROR_TITLE="Some fields do not comply with the syntactic rules"
  EXPECTED_ERROR_DETAIL="Required value"
  EXPECTED_ERROR_FIELD="spec.sgCluster"

  assert_api_error "$ERROR_RESPONSE"

  INVALID_DBOPS_NAME="$(cat "$LOG_PATH/dbops-repack.json" | jq '.metadata.name = "test-pg12.8"' )"

  echo "$INVALID_DBOPS_NAME" > "$LOG_PATH/invalid-dbops-name.json"

  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sgdbops" -n "$CLUSTER_NAMESPACE"  -d "$LOG_PATH/invalid-dbops-name.json" -e '-X POST -w %{http_code} -o /dev/null')"

  assert_string_equal "422" "$HTTP_STATUS"

  ERROR_RESPONSE="$(run_curl -r "stackgres/sgdbops" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/invalid-dbops-name.json" -e '-X POST')"

  EXPECTED_ERROR_TYPE="constraint-violation"
  EXPECTED_ERROR_TITLE="Some fields do not comply with the syntactic rules"
  EXPECTED_ERROR_DETAIL="metadata.name in body should match '^[a-z]([-a-z0-9]*[a-z0-9])?$'"
  EXPECTED_ERROR_FIELD="metadata.name"

  assert_api_error "$ERROR_RESPONSE"
}

test_authentication_api_error() {
  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgdbops" -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sgdbops/$DBOPS_NAME" -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgdbops" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/dbops-repack.json" -e '-X POST -w %{http_code} -o /dev/null')"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgdbops" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/dbops-repack.json" -e '-X PUT -w %{http_code} -o /dev/null')"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sgdbops" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/dbops-repack.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  check_authentication_error
}

check_authentication_error() {
  if [ "$HTTP_STATUS" = "401" ]
  then
    echo "Request returned expected authentication error"
    return 0
  else
    echo "Request returned unexpected response status $HTTP_STATUS instead of the expected authentication error."
    return 1
  fi
}

